package com.dstz.agilebpm.sys.autoconfiguration;

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.dstz.base.core.cache.ICache;
import com.dstz.base.core.cache.impl.MemoryCache;
import com.dstz.sys.redis.RedisCache;
import com.dstz.sys.util.RedisPubsub;

/**
 * 缓存相关配置
 *
 * @author jeff
 * @date 2018-8-12 22:36:19
 */
@Configuration
@SuppressWarnings("rawtypes")
@Order(Integer.MAX_VALUE)
public class CacheAutoConfiguration {
	@Autowired RedisConnectionFactory connectionFactory;
	@Autowired MessageListenerAdapter listenerAdapter;
	@Autowired(required=false) RedisMessageListenerContainer container;
	@Value("${ab.cache.type}") String abCacheType;

    @Bean
    @ConditionalOnExpression("#{!T(org.springframework.util.ClassUtils).isPresent('com.dstz.agilebpm.sys.autoconfiguration.cache.AbRedisCacheConfiguration', null)}")
    public ICache iCache() {
        return "redis".equalsIgnoreCase(abCacheType) ? new RedisCache<>() : new MemoryCache<>();
    }
    
    @Bean
    @ConditionalOnExpression("#{!T(org.springframework.util.ClassUtils).isPresent('com.dstz.agilebpm.sys.autoconfiguration.cache.AbRedisCacheConfiguration', null) && 'redis'.equalsIgnoreCase('${ab.cache.type}')}")
    RedisMessageListenerContainer container() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        listenerAdapter.setSerializer(RedisSerializer.java());
        container.addMessageListener(listenerAdapter, new PatternTopic(RedisPubsub.CHANNEL));
        return container;
    }
    
    /** 使用redis时启用分布式锁功能，锁定30秒之后自动解锁，定时任务精确到分钟，在前10秒内完成加锁，通过executes次数来模拟轮询 */
    @ConditionalOnProperty(prefix = "ab.cache", name = "type", havingValue = "redis")
	@Bean(destroyMethod = "destroy")  
	public RedisLockRegistry redisLockRegistry() {
    	if(container != null) {
	    	listenerAdapter.setSerializer(RedisSerializer.java());
	    	container.addMessageListener(listenerAdapter, new PatternTopic(RedisPubsub.CHANNEL));
    	}
	    return new RedisLockRegistry(connectionFactory, "redis-lock-registry", 30000L);  
	}

    @Bean(name = "taskExecutor")
    @ConditionalOnExpression("#{!T(org.springframework.util.ClassUtils).isPresent('com.dstz.agilebpm.sys.autoconfiguration.cache.AbRedisCacheConfiguration', null)}")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(1000);
        taskExecutor.setKeepAliveSeconds(300);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return taskExecutor;
    }

}
